﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Xeml.Document.Contracts;
using Xeml.Document;
using Mpi.Common.Collections;
using Xeml.Sampling;
using System.IO;

namespace CompilerControls
{
    public partial class CompileCtrl : UserControl
    {

        private IDocument _xemlDoc;

        public CompileCtrl()
        {
            InitializeComponent();
        }

        DataTable _lastTable = null;
        public void Setup(IDocument xemlDoc)
        {
            _xemlDoc = xemlDoc;


        }

        private void Compile()
        {
            if (_xemlDoc != null && _xemlDoc.DocumentResources.DataProvider.Count > 0)
            {
                DataTable target = Format(_xemlDoc);


                foreach (var providerRes in _xemlDoc.DocumentResources.DataProvider)
                {
                    if (providerRes.ComponentState == ComponentLoadState.Loaded)
                    {
                        if (_xemlDoc.ProviderDataMappings.ContainsKey(providerRes.FriendlyName))
                        {
                            var x = from sim in _xemlDoc.ProviderDataMappings[providerRes.FriendlyName]
                                    select sim;
                            KeyKeyValueCollection<string, int, object> data = providerRes.Provider.QueryData(x.ToList());
                            DataTable analytes = DataToTable(data, providerRes.FriendlyName);
                            target = Join(target, "SampleId", analytes, "$SampleId$");
                        }
                    }
                }
                _lastTable = target;
                BindToGrid(target);
            }
        }



        private void BindToGrid(DataTable dt)
        {

            _lastTable = dt;
            dt.DefaultView.Sort = "SampleId";
            kryptonDataGridView1.ColumnHeadersHeight = 100;


            DataGridViewColumn[] columns = new DataGridViewColumn[dt.Columns.Count];
            kryptonDataGridView1.RowCount = dt.Rows.Count;
            kryptonDataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            for (int i = 0; i < columns.Length; ++i)
            {
                DataGridViewColumn column = new DataGridViewTextBoxColumn();
                column.Name = dt.Columns[i].ColumnName;
                column.HeaderCell.Style.WrapMode = DataGridViewTriState.True;
                column.FillWeight = 1;
                column.HeaderText = dt.Columns[i].Caption;
                columns[i] = column;
            }
            kryptonDataGridView1.Columns.Clear();
            kryptonDataGridView1.RowCount = dt.Rows.Count;
            this.kryptonDataGridView1.Columns.AddRange(columns);
            kryptonDataGridView1.Columns.RemoveAt(0);
            
        }


        private DataTable DataToTable(KeyKeyValueCollection<string, int, object> data, string providerScope)
        {
            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("$SampleId$");
            dc.AllowDBNull = true;
            dc.Caption = "Sample";
            dc.DataType = typeof(int);

            dt.Columns.Add(dc);
            dt.PrimaryKey = new DataColumn[] { dc };
            foreach (string a in data.FirstLevelKeys())
            {
                dc = new DataColumn(a + "_" + providerScope);
                dc.AllowDBNull = true;
                dc.Caption = a;
                dt.Columns.Add(dc);
            }

            List<int> rows = new List<int>();
            foreach (string a in data.FirstLevelKeys())
            {
                foreach (int i in data.SecondLevelKeys(a))
                {
                    if (!rows.Contains(i))
                        rows.Add(i);
                }
            }
            foreach (int i in rows)
            {
                DataRow dr = dt.NewRow();


                foreach (DataColumn x in dt.Columns)
                {
                    if (x.ColumnName == "$SampleId$")
                        dr[x] = i;
                    else
                    {
                        if (data.Contains(x.Caption, i))
                            dr[x] = data[x.Caption, i];
                        else
                            dr[x] = "NA";
                    }
                }

                dt.Rows.Add(dr);
            }

            return dt;
        }

        private DataTable Join(DataTable dt1, string colName1, DataTable dt2, string colName2)
        {
            DataTable ret = new DataTable();
            foreach (DataColumn dc in dt1.Columns)
            {
                DataColumn newDc = new DataColumn(dc.ColumnName);
                newDc.DataType = dc.DataType;
                newDc.Caption = dc.Caption;
                ret.Columns.Add(newDc);
            }

            foreach (DataColumn dc in dt2.Columns)
            {
                if (dc.ColumnName != colName2)
                {
                    DataColumn newDc = new DataColumn(dc.ColumnName);
                    newDc.DataType = dc.DataType;
                    newDc.Caption = dc.Caption;
                    if (!ret.Columns.Contains(dc.ColumnName))
                    {
                        ret.Columns.Add(newDc);
                    }
                }
            }

            foreach (DataRow dr in dt1.Rows)
            {

                DataRow newDr = ret.NewRow();
                foreach (DataColumn dc in dt1.Columns)
                {
                    newDr[dc.ColumnName] = dr[dc];
                }
                DataRow dr2 = FindRow(dt2, colName2, dr[colName1]);
                if (dr2 != null)
                {
                    foreach (DataColumn dc in dt2.Columns)
                    {
                        if (dc.ColumnName != colName2)
                        {
                            newDr[dc.ColumnName] = dr2[dc];
                        }
                    }
                }
                ret.Rows.Add(newDr);
            }

            return ret;
        }

        private DataRow FindRow(DataTable dt2, string colName2, object p)
        {
            foreach (DataRow dr in dt2.Rows)
            {
                if (dr[colName2].Equals(p))
                    return dr;
            }
            return null;
        }

        StandardTableFormatter stf = new StandardTableFormatter();
        ParameterColumnEmitter pce;
        SampleColumnEmitter sce;
        EventColumnEmitter ece;

        public DataTable Format(IDocument xemlDoc)
        {



            _xemlDoc = xemlDoc;
            stf.Emitter.Clear();
            pce = new ParameterColumnEmitter();
            sce = new SampleColumnEmitter();
            ece = new EventColumnEmitter();
            // oce = new ObPointColumnEmitter();
            sce.Emit(xemlDoc);
            pce.Emit(xemlDoc);
            ece.Emit(xemlDoc);
            // oce.Emit(this.XemlDoc);



            stf.Emitter.Add(sce);
            stf.Emitter.Add(pce);
            stf.Emitter.Add(ece);
            // stf.Emitter.Add(oce);


            //PopulateSampleColumnEmitterTree(sce);
            //PopulateParameterColumnEmitterTree(pce);
            //PopulateEventColumnEmitterTree(ece);



            return stf.Format(xemlDoc);
            //_tableFormatterWorker.ReportProgress(50);
            //this.kryptonDataGridView1.DataSource = _table;
            //foreach (DataGridViewColumn var in kryptonDataGridView1.Columns)
            //{
            //    DataTable dt = (DataTable)kryptonDataGridView1.DataSource;
            //    var.HeaderText = dt.Columns[var.DataPropertyName].Caption;

            //}


        }

        private void kryptonButtonCompile_Click(object sender, EventArgs e)
        {
            Compile();
        }

        private void kryptonButtonExport_Click(object sender, EventArgs e)
        {

            ExportDialog ed = new ExportDialog(_xemlDoc.Name);
            if (ed.ShowDialog() == DialogResult.OK)
            {
                FileInfo fi = new FileInfo(ed.FilePath);
                WriteCSV(ed.FilePath, ed.Separator, ed.LineBreak, ed.Encoding, _lastTable);
                WriteRScript(fi.FullName.Replace(fi.Extension, ".r"), ed.FilePath, ed.Separator, ed.PathSeparator);
            }
        }

        private void WriteRScript(string path, string datafile, string sep, string pathSep)
        {
            StringBuilder sb = new StringBuilder();
            if (sep == "\t")
            {
                if (pathSep == "\\")
                    sb.AppendFormat("xemldatatable <- read.table(\"{0}\", sep=\"{1}\", header=TRUE, quote = \"\\'\")\r\n", datafile.Replace("\\", "\\\\"), "\\t");
                else
                    sb.AppendFormat("xemldatatable <- read.table(\"{0}\", sep=\"{1}\", header=TRUE, quote = \"\\'\")\r\n", datafile.Replace("\\", "/"), "\\t");
            }
            else
            {
                if (pathSep == "\\")
                    sb.AppendFormat("xemldatatable <- read.table(\"{0}\", sep=\"{1}\", header=TRUE, quote = \"\\'\")\r\n", datafile.Replace("\\", "\\\\"), sep);
                else
                    sb.AppendFormat("xemldatatable <- read.table(\"{0}\", sep=\"{1}\", header=TRUE, quote = \"\\'\")\r\n", datafile.Replace("\\", "/"), sep);
            }
            File.WriteAllText(path, sb.ToString());
        }

        private void WriteCSV(string path, string sep, string linebreak, Encoding enc, DataTable table)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < table.Columns.Count; i++)
            {
                sb.AppendFormat("{0}{1}", table.Columns[i].Caption.Replace("\r\n", "_").Replace(sep, ""), sep);//
            }
            sb.Remove(sb.Length - 1, 1);
            sb.Append(linebreak);
            foreach (DataRow row in table.Rows)
            {
                foreach (var val in row.ItemArray)
                {
                    sb.AppendFormat("{0}{1}", val.ToString().Replace("\r\n", "|").Replace(sep, ""), sep);
                }
                sb.Remove(sb.Length - 1, 1);
                sb.Append(linebreak);
            }

            File.WriteAllText(path, sb.ToString(), enc);
        }

        private void kryptonDataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            e.Value = _lastTable.DefaultView[e.RowIndex].Row[e.ColumnIndex];

            //   e.Value = _lastTable.Rows[e.RowIndex].ItemArray[e.ColumnIndex];


        }

        private void kryptonDataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            string sortasc = string.Format("[{0}] asc", kryptonDataGridView1.Columns[e.ColumnIndex].Name);
            string sortdesc = string.Format("[{0}] desc", kryptonDataGridView1.Columns[e.ColumnIndex].Name);

            if (_lastTable.DefaultView.Sort == sortasc)
                _lastTable.DefaultView.Sort = sortdesc;
            else //(_lastTable.DefaultView.Sort == sortasc)
                _lastTable.DefaultView.Sort = sortasc;
            //else

            //_lastTable.DefaultView.Sort = kryptonDataGridView1.Columns[e.ColumnIndex].Name;
            // _lastTable.DefaultView.
            kryptonDataGridView1.Refresh();


        }

    }
}
